/**
 * ex14. 文件与目录
 *
 * @author 90598
 * @date 2020/11/17
 */
package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

func main() {
	/*
		读取文件
	*/
	fmt.Println("============================ 读取文件 ============================")
	path := "src/main/main.go"

	// fmt.Println("---------------------------- file ----------------------------")
	// readFile1(path) // 以流读取

	// fmt.Println("\n---------------------------- bufio ----------------------------")
	// readFile2(path) // 以流读取

	fmt.Println("\n---------------------------- ioutil ----------------------------")
	readFile3(path)

	/*
		写入文件
	*/
	fmt.Println("\n============================ 写入文件 ============================")
	path = "./text.txt"
	// fmt.Println("\n---------------------------- file ----------------------------")
	// writeFile1(path)

	// fmt.Println("\n---------------------------- bufio ----------------------------")
	// writeFile2(path)

	fmt.Println("\n---------------------------- ioutil ----------------------------")
	writeFile3(path)

	/*
		创建目录
	*/
	fmt.Println("\n============================ 创建目录 ============================")
	// mkdir命令（想起了linux），若目标目录已存在则会返回err
	os.Mkdir("src/main/tmp", 666)
	// 多级目录，即使已存在也不会返回err
	os.MkdirAll("src/main/tmp/tmp2/tmp3", 666)

	/*
		重命名
	*/
	fmt.Println("\n============================ 重命名 ============================")
	os.Rename("src/main/tmp", "src/main/tmp0")

	/*
		删除目录
	*/
	fmt.Println("\n============================ 删除目录/文件 ============================")
	// 同样的，目录或文件不存在时，只有Remove会返回err，而RemoveAll不会
	os.Remove("./text.txt")
	os.Remove("src/main/tmp/tmp2/tmp3")
	os.RemoveAll("src/main/tmp0")
}

func readFile1(path string) {
	// 只读方式打开文件
	file, err := os.Open(path)
	if err != nil {
		fmt.Println(err)
		return
	}
	// 关闭文件流
	defer file.Close()

	var strSlice []byte
	slice := make([]byte, 128)
	for {
		// 读取文件
		n, err := file.Read(slice)
		// 读取完毕
		if err == io.EOF {
			fmt.Println("over")
			break
		}
		if err != nil {
			fmt.Println("读取失败：", err)
			return
		}
		// [:n]是为了防止最后后一批数据无法满足128字节
		strSlice = append(strSlice, slice[:n]...)
	}
	fmt.Println(string(strSlice))
}

func readFile2(path string) {
	// 只读方式打开文件
	file, err := os.Open(path)
	if err != nil {
		fmt.Println(err)
		return
	}
	// 关闭文件流
	defer file.Close()

	var str string
	reader := bufio.NewReader(file)
	for {
		// 以行读取文件
		line, err := reader.ReadString('\n')
		// 读取完毕
		if err == io.EOF {
			fmt.Println("over")
			str += line // 最后可能还有剩余未拼接的已读取的字符串
			break
		}
		if err != nil {
			fmt.Println("读取失败：", err)
			return
		}
		str += line
	}
	fmt.Println(str)
}

func readFile3(path string) {
	byteStr, err := ioutil.ReadFile(path)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(byteStr))
}

func writeFile1(path string) {
	// name：文件名
	// flag：打开文件的模式
	//	模式详见源码 file.go 中的常量
	// perm：文件权限，一个八进制数
	//	rwx - 421
	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 666)
	defer file.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	// f.Write(b []byte) 通过字节切片写入
	file.WriteString("直接写入字符串\r\n")
}

func writeFile2(path string) {
	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 666)
	defer file.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	writer := bufio.NewWriter(file)
	writer.WriteString("通过bufio写入字符串") // 写入缓存
	writer.Flush()                     // 缓存刷新到磁盘
}

// 只能清空重写
func writeFile3(path string) {
	err := ioutil.WriteFile(path, []byte("通过ioutil写入字符串"), 666)
	if err != nil {
		fmt.Println(err)
		return
	}
}
